/**
 * 
 */
package info.niwota.fwrite;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;

import android.os.Environment;

/**
 * @author qiangli
 * 
 */
public final class SDCard {
	private static final File sdcard = Environment
			.getExternalStorageDirectory();

	private SDCard() {
	}

	public static File getCacheDir() {
		File dir = new File(sdcard, "info.niwota.fwrite/cache");
		if (!dir.isDirectory()) {
			if (!dir.mkdirs()) {
				return null;
			}
		}
		return dir;
	}

	public static File getNoteDir() {
		// File dir = new File(sdcard, "fwrite");
		File dir = new File(sdcard, "info.niwota.fwrite/archive");
		if (!dir.isDirectory()) {
			if (!dir.mkdirs()) {
				return null;
			}
		}
		return dir;
	}
	
	public static File getTopDir() {
		File dir = new File(sdcard, "info.niwota.fwrite/top");
		if (!dir.isDirectory()) {
			if (!dir.mkdirs()) {
				return null;
			}
		}
		return dir;
	}

	public static File getRoot() {
		File dir = new File(sdcard, "info.niwota.fwrite");
		if (!dir.isDirectory()) {
			if (!dir.mkdirs()) {
				return null;
			}
		}
		return dir;
	}

	public static boolean hasMessage(String peer) {
		File file = new File(sdcard, "info.niwota.fwrite/inbox/" + peer);
		return (file.exists() && file.length() > 0);
	}

	public synchronized static void saveMessage(String peer, String note)
			throws IOException {
		File file = new File(sdcard, "info.niwota.fwrite/inbox/" + peer);
		File inbox = file.getParentFile();
		if (!inbox.exists()) {
			inbox.mkdirs();
		}
		FileWriter fw = new FileWriter(file, true);
		try {
			fw.write(note);
		} finally {
			fw.close();
		}
	}

	public synchronized static void ensureSession(String peer)
			throws IOException {
		File file = new File(sdcard, "info.niwota.fwrite/inbox/" + peer);
		if (!file.exists()) {
			File inbox = file.getParentFile();
			if (!inbox.exists()) {
				inbox.mkdirs();
			}
			//
			touch(file);
		}
	}

	public synchronized static void removeSession(String peer) {
		File file = new File(sdcard, "info.niwota.fwrite/inbox/" + peer);
		if (file.exists()) {
			file.delete();
		}
		//
		File sfile = new File(sdcard, "info.niwota.fwrite/chat/" + peer
				+ ".ser");
		if (sfile.exists()) {
			sfile.delete();
		}
	}

	public synchronized static void saveSession(String peer, DocumentView doc)
			throws Exception {
		File file = new File(sdcard, "info.niwota.fwrite/chat/" + peer
				+ ".ser");
		File dir = file.getParentFile();
		if (!dir.exists()) {
			dir.mkdirs();
		}
		
		OutputStream os = new FileOutputStream(file);
		serializeDoc(doc, os);
		os.close();
	}
	
	public static void serializeDoc(DocumentView doc, OutputStream os) throws Exception {
		ObjectOutputStream out = new ObjectOutputStream(os);
		try {
			ArrayList<Line> lines = doc.getLines();

			final int lineCount = lines.size();

			out.writeInt(lineCount);
			for (int i = 0; i < lineCount; i++) {
				out.writeObject(lines.get(i));
			}
			out.writeObject(doc.state);
		} finally {
			out.close();
		}
	}

	public synchronized static void restoreSession(String peer, DocumentView doc)
			throws Exception {
		//
		File sfile = new File(sdcard, "info.niwota.fwrite/chat/" + peer
				+ ".ser");

		if (!sfile.exists()) {
			return;
		}

		InputStream is = new FileInputStream(sfile);
		deserializeDoc(is, doc);
		is.close();
	}

	public static void deserializeDoc(InputStream is, DocumentView doc) throws Exception {
		ObjectInputStream in = new ObjectInputStream(is);
		try {
			doc.clear();
			
			final int lineCount = in.readInt();
			for (int i = 0; i < lineCount; i++) {
				doc.addLine((Line) in.readObject());
			}

			doc.state = (DocumentState) in.readObject();
		} finally {
			in.close();
		}
	}

	public synchronized static File getMessage(String peer) throws IOException {
		File file = new File(sdcard, "info.niwota.fwrite/inbox/" + peer);
		
		if (file.exists() && file.length() > 0) {
			//got messages
			File nfile = new File(sdcard, "info.niwota.fwrite/inbox/~" + peer);
			file.renameTo(nfile);
			
			//recreate to keep session
			touch(file);
			//
			return nfile;
		}
		return null;
	}

	private static void touch(File file) throws IOException {
		FileWriter fw = new FileWriter(file, true);
		fw.close();
	}

	public static File[] listSessions() {
		File dir = new File(sdcard, "info.niwota.fwrite/inbox");
		return dir.listFiles(sessionFilter);
	}

	public static File[] listMessages() {
		File dir = new File(sdcard, "info.niwota.fwrite/inbox");
		return dir.listFiles(messageFilter);
	}

	private static final FilenameFilter sessionFilter = new FilenameFilter() {
		public boolean accept(File dir, String filename) {
			return !filename.startsWith("~");
		}
	};
	
	private static final FileFilter messageFilter = new FileFilter() {
		public boolean accept(File file) {
			return !file.getName().startsWith("~") && file.length() > 0;
		}
	};
}
